#!/bin/bash
#
#********************************************************************
#Author:                songliangcheng
#QQ:                    2192383945
#Date:                  2023-02-18 16:54:54
#FileName：             install-kubernetes.sh
#URL:                   http://blog.mykernel.cn
#Description：          Kubernetes 版本获取 https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#before-you-begin
#Copyright (C):        2023 All rights reserved
#********************************************************************
#描述:
#--cni-plugin-version 选项必须传递
#--download-dir 选项可以省略
#--crictl-version 选项必须传递
source <(curl -sSLf https://gitee.com/slcnx/tools/raw/master/parse_cmd.sh | sed 's/\r//g')
source <(curl -sSLf https://gitee.com/slcnx/tools/raw/master/scripts/proxy/addosproxy.sh)
CONFIG='
key    ,argument    ,isempty    ,desc    
################
--http-proxy    ,_HTTP_PROXY    ,0    ,script级 http代理
--no-proxy    ,_NO_PROXY    ,1    ,script级 哪些IP可以不代理，给127.0.0.1,localhost追加
################
--cni-plugin-version    ,CNI_PLUGINS_VERSION    ,0    ,安装 CNI 插件（大多数 pod 网络都需要）：
--download-dir    ,DOWNLOAD_DIR    ,1    ,该DOWNLOAD_DIR变量必须设置为可写目录。如果您正在运行 Flatcar Container Linux，请将DOWNLOAD_DIR="/opt/bin".。默认/opt/kubernetes/bin/
--crictl-version    ,CRICTL_VERSION    ,0    ,安装 crictl（kubeadm / Kubelet 容器运行时接口 (CRI) 需要）
--release-version    ,RELEASE_VERSION    ,0    ,kubelet发布版本,v0.4.0
--release    ,RELEASE    ,0    , eg: v1.23.16; kubernetes版本. https://github.com/kubernetes/kubernetes/tags; 如果版本>=1.24, cri-dockerd不可以使用，相当于不能使用开源的docker


###############################
--i-k8s    ,    ,1    ,安装k8s master节点吗? 默认不安装，只初始化。传递之后就安装

--apiserver-advertise-address    ,apiserver_advertise_address    ,1    , api地址 接口的地址
--apiserver-bind-port    ,apiserver_bind_port    ,1    ,api端口 [默认6443]
--control-plane-endpoint    ,control_plane_endpoint    ,1    ,控制平面api统一地址
--cri-socket    ,cri_socket    ,1    ,cri接口地址 [默认 unix:////var/run/cri-dockerd.sock]
--node-name    ,node_name    ,1    ,当前节点的节点名 [默认 与apiserver_advertise_address一样]
--pod-network-cidr    ,pod_network_cidr    ,1    ,pod网络 [默认10.244.0.0/16 ]
--service-cidr    ,service_cidr    ,1    ,service网络 [默认10.96.0.0/12]
--service-dns-domain    ,service_dns_domain    ,1    ,集群域名 [默认 cluster.local]
--token-ttl    ,token_ttl    ,1    ,token过期时间，[默认12h]
--master-schedule    ,    ,1    ,默认不可以调度
'


parse_cmd $@

export _HTTP_PROXY=$_HTTP_PROXY
export _NO_PROXY=$_NO_PROXY
: ${CURRENT_DIR:="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"}

: ${apiserver_bind_port:=6443}
: ${cri_socket:=unix:////var/run/cri-dockerd.sock}
: ${pod_network_cidr:=10.244.0.0/16}
: ${service_cidr:=10.96.0.0/12}
: ${service_dns_domain:=cluster.local}
: ${token_ttl:=12h}
# $apiserver_advertise_address  $control_plane_endpoint 不传也没有事，在后面会检查是否空.
echo "$apiserver_advertise_address $apiserver_bind_port $control_plane_endpoint $cri_socket $node_name $pod_network_cidr $service_cidr $service_dns_domain $token_ttl --is-init state: $(getflag '--is-init') "

# runtime 

echo $CNI_PLUGINS_VERSION $CRICTL_VERSION  $RELEASE_VERSION $RELEASE

: ${DOWNLOAD_DIR:=/opt/kubernetes/bin}
echo "$DOWNLOAD_DIR "

####################################
#安装 CNI 插件（大多数 pod 网络都需要）：
#CNI_PLUGINS_VERSION="v1.1.1"
#DOWNLOAD_DIR="/opt/kubernetes/bin"
#CRICTL_VERSION="v1.25.0"
#####################################


# init
function ipvs_init() {
# ipvs
apt install ipset ipvsadm -y
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack
modprobe -- br_netfilter
lsmod | grep -e ip_vs -e nf_conntrack
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
EOF
}

function pkgs_init() {
  apt install conntrack socat -y
}


function cni_init() {
#CNI_PLUGINS_VERSION="v1.1.1"
ARCH="amd64"
DEST="/opt/cni/bin"
sudo mkdir -p "$DEST"
if ! [ "$(ls -A $DEST)" ]; then
  mycurl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_PLUGINS_VERSION}/cni-plugins-linux-${ARCH}-${CNI_PLUGINS_VERSION}.tgz" | sudo tar -C "$DEST" -xz
fi
}
function crictl_init() {
# Install crictl (required for kubeadm / Kubelet Container Runtime Interface (CRI))
#DOWNLOAD_DIR="/opt/kubernetes/bin"
mkdir -pv $DOWNLOAD_DIR
#CRICTL_VERSION="v1.25.0"
ARCH="amd64"
if ! [ "$(ls -A $DOWNLOAD_DIR)" ]; then
mycurl -L "https://github.com/kubernetes-sigs/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-${ARCH}.tar.gz" | sudo tar -C $DOWNLOAD_DIR -xz
fi
}

k8sbin_init() {
#Install kubeadm, kubelet, kubectl and add a kubelet systemd service:
#RELEASE="$(mycurl -sSL https://dl.k8s.io/release/stable.txt)"

ARCH="amd64"
cd $DOWNLOAD_DIR
[ -f $DOWNLOAD_DIR/kubeadm -a -f $DOWNLOAD_DIR/kubelet ] || {
mywget https://dl.k8s.io/${RELEASE}/kubernetes-node-linux-$ARCH.tar.gz
tar xvf kubernetes-node-linux-amd64.tar.gz -C /opt/kubernetes/bin kubernetes/node/bin/ --strip-components=3
rm -f kubernetes-node-linux-amd64.tar.gz
}
sudo chmod +x $DOWNLOAD_DIR/*


# kubelet
#RELEASE_VERSION="v0.4.0"
[ -f /etc/systemd/system/kubelet.service ] || {
mycurl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/kubepkg/templates/latest/deb/kubelet/lib/systemd/system/kubelet.service" | sed "s:/usr/bin:${DOWNLOAD_DIR}:g" | sudo tee /etc/systemd/system/kubelet.service
}
sudo mkdir -p /etc/systemd/system/kubelet.service.d

[ -f /etc/systemd/system/kubelet.service.d/10-kubeadm.conf ] || {
mycurl -sSL "https://raw.githubusercontent.com/kubernetes/release/${RELEASE_VERSION}/cmd/kubepkg/templates/latest/deb/kubeadm/10-kubeadm.conf" | sed "s:/usr/bin:${DOWNLOAD_DIR}:g" | sudo tee /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
}
# Enable and start kubelet:
systemctl daemon-reload
systemctl unmask kubelet
systemctl enable --now kubelet

echo "export PATH=$DOWNLOAD_DIR:\$PATH" > /etc/profile.d/Z99-kubernetes.sh
source  /etc/profile.d/Z99-kubernetes.sh
kubectl version --client
kubectl version --client --output=yaml
kubectl completion bash >> ~/.bashrc
}


function otherinit() {
  sed -i 's/^.*swap.*$/#&/g' /etc/fstab
  swapoff -a
}


function  install_k8s() {
  check_empty apiserver_advertise_address control_plane_endpoint
  : ${node_name:=$apiserver_advertise_address}

  cd $CURRENT_DIR
  join_log=./kubeadm_join.log
  kubeadm init --apiserver-advertise-address $apiserver_advertise_address  --apiserver-bind-port $apiserver_bind_port --control-plane-endpoint $control_plane_endpoint --cri-socket $cri_socket  --kubernetes-version $RELEASE  --node-name $apiserver_advertise_address --pod-network-cidr $pod_network_cidr    --service-cidr $service_cidr --service-dns-domain $service_dns_domain --token-ttl $token_ttl  --upload-certs   2>&1 | tee  $join_log

  cat <<EOF
===================================
已经将以上的日志记录到文件: $join_log
===================================
EOF
}


install_flannel() {
  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config


  if [ $(getflag '--master-schedule') -eq 1 ]; then
    kubectl taint node --all node-role.kubernetes.io/master:NoSchedule-
  fi

  cd $CURRENT_DIR
  network_yaml=./kube-flannel.yaml
  mycurl -SsfL https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml | sed "s@10.244.0.0/16@$pod_network_cidr@g" | sed 's@"Type": "vxlan"@"Type": "vxlan","DirectRouting": true@g' > $network_yaml
  kubectl apply -f $network_yaml
}

function main() {
  pkgs_init
  ipvs_init
  # pod network
  cni_init
  # Install crictl (required for kubeadm / Kubelet Container Runtime Interface (CRI))
  crictl_init
  # Install kubeadm, kubelet, kubectl and add a kubelet systemd service: and kubectl
  k8sbin_init

  # otherinit
  otherinit

  if [ $(getflag '--i-k8s') -eq 1 ]; then
    # install kubernetes
    install_k8s

    # install network
    install_flannel
  fi
}

main
